package com.victor.loading.rotate;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Arc;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;

/**
 * RotateLoading
 * Created by Victor on 2015/4/28.
 */
public class RotateLoading extends Component implements Component.DrawTask, Component.LayoutRefreshedListener {
    private static final int DEFAULT_WIDTH = 6;
    private static final int DEFAULT_SHADOW_POSITION = 2;
    private static final int DEFAULT_SPEED_OF_DEGREE = 10;

    private Paint mPaint;

    private RectFloat loadingRectF;
    private RectFloat shadowRectF;

    private int topDegree = 10;
    private int bottomDegree = 190;

    private float arc;

    private int width;

    private boolean changeBigger = true;

    private int shadowPosition;

    private boolean isStart = false;

    private int color;

    private int speedOfDegree;

    private float speedOfArc;

    public RotateLoading(Context context) {
        super(context);
        initView(context, null);
    }

    public RotateLoading(Context context, AttrSet attrs) {
        super(context, attrs);
        initView(context, attrs);
    }

    public RotateLoading(Context context, AttrSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context, attrs);
    }

    private void initView(Context context, AttrSet attrs) {
        setLayoutRefreshedListener(this::onRefreshed);
        addDrawTask(this::onDraw);
        new StyledAttributes(attrs, context);

        speedOfArc = speedOfDegree / 4;
        mPaint = new Paint();
        mPaint.setColor(new Color(color));
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE_STYLE);
        mPaint.setStrokeWidth(width);
        mPaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);

        onRefreshed(this);
        invalidate();
    }

    @Override
    public void onRefreshed(Component component) {
        arc = 10;
        int width = component.getWidth();
        int height = component.getHeight();

        loadingRectF = new RectFloat(2 * this.width, 2 * this.width, width - 2 * this.width, height - 2 * this.width);
        shadowRectF = new RectFloat(2 * this.width + shadowPosition, 2 * this.width + shadowPosition,
                width - 2 * this.width + shadowPosition, height - 2 * this.width + shadowPosition);
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (!isStart) {
            return;
        }

        mPaint.setColor(Color.GREEN);
        canvas.drawArc(shadowRectF, new Arc(topDegree, arc, false), mPaint);
        canvas.drawArc(shadowRectF, new Arc(bottomDegree, arc, false), mPaint);

        mPaint.setColor(new Color(color));
        canvas.drawArc(loadingRectF, new Arc(topDegree, arc, false), mPaint);
        canvas.drawArc(loadingRectF, new Arc(bottomDegree, arc, false), mPaint);

        topDegree += speedOfDegree;
        bottomDegree += speedOfDegree;
        if (topDegree > 360) {
            topDegree = topDegree - 360;
        }
        if (bottomDegree > 360) {
            bottomDegree = bottomDegree - 360;
        }

        if (changeBigger) {
            if (arc < 160) {
                arc += speedOfArc;
                invalidateView();
            }
        } else {
            if (arc > speedOfDegree) {
                arc -= 2 * speedOfArc;
                invalidateView();
            }
        }
        if (arc >= 160 || arc <= 10) {
            changeBigger = !changeBigger;
            invalidateView();
        }
    }

    public void setLoadingColor(int color) {
        this.color = color;
    }

    public int getLoadingColor() {
        return color;
    }

    private void invalidateView() {
        getContext().getUITaskDispatcher().asyncDispatch(this::invalidate);
    }

    public void start() {
        startAnimator();
        isStart = true;
        invalidate();
    }

    public void stop() {
        stopAnimator();
        invalidate();
    }

    public boolean isStart() {
        return isStart;
    }

    private void startAnimator() {
        AnimatorProperty scaleXAnimator = this.createAnimatorProperty().scaleXFrom(0f).scaleX(1f);
        AnimatorProperty scaleYAnimator = this.createAnimatorProperty().scaleYFrom(0f).scaleY(1f);
        scaleXAnimator.setDuration(300);
        scaleXAnimator.setCurveType(Animator.CurveType.LINEAR);
        scaleYAnimator.setDuration(300);
        scaleYAnimator.setCurveType(Animator.CurveType.LINEAR);
        AnimatorGroup animatorSet = new AnimatorGroup();
        animatorSet.runParallel(scaleXAnimator, scaleYAnimator);
        animatorSet.start();
    }

    private void stopAnimator() {
        AnimatorProperty scaleXAnimator = this.createAnimatorProperty().scaleXFrom(1f).scaleX(0f);
        AnimatorProperty scaleYAnimator = this.createAnimatorProperty().scaleYFrom(1f).scaleY(0f);
        scaleXAnimator.setDuration(300);
        scaleXAnimator.setCurveType(Animator.CurveType.LINEAR);
        scaleYAnimator.setDuration(300);
        scaleYAnimator.setCurveType(Animator.CurveType.LINEAR);
        AnimatorGroup animatorSet = new AnimatorGroup();
        animatorSet.runParallel(scaleXAnimator, scaleYAnimator);
        animatorSet.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) { }

            @Override
            public void onStop(Animator animator) {
                isStart = false;
            }

            @Override
            public void onCancel(Animator animator) { }

            @Override
            public void onEnd(Animator animator) { }

            @Override
            public void onPause(Animator animator) { }

            @Override
            public void onResume(Animator animator) { }
        });
        animatorSet.start();
    }

    public int dpToPx(Context context, float dpVal) {
        if (dpVal <= 0) {
            return 0;
        }
        return (int) (context.getResourceManager().getDeviceCapability().screenDensity / 160 * dpVal);
    }

    /**
     * Parse Style attributes
     */
    private class StyledAttributes {
        private final String colorValue = "loading_color";
        private final String widthValue = "loading_width";
        private final String shadowValue = "shadow_position";
        private final String speedValue = "loading_speed";

        StyledAttributes(AttrSet attrs, Context context) {
            color = attrs.getAttr(colorValue).isPresent()
                    ? attrs.getAttr(colorValue).get().getIntegerValue() : Color.WHITE.getValue();
            width = attrs.getAttr(widthValue).isPresent()
                    ? attrs.getAttr(widthValue).get().getIntegerValue() : dpToPx(context, DEFAULT_WIDTH);
            shadowPosition = attrs.getAttr(shadowValue).isPresent()
                    ? attrs.getAttr(shadowValue).get().getIntegerValue() : DEFAULT_SHADOW_POSITION;
            speedOfDegree = attrs.getAttr(speedValue).isPresent()
                    ? attrs.getAttr(speedValue).get().getIntegerValue() : DEFAULT_SPEED_OF_DEGREE;
        }
    }

}
